package com.atguigu.gulimall.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.exception.NoStockException;
import com.atguigu.common.to.SkuHasStockTO;
import com.atguigu.common.to.mq.OrderDetailTo;
import com.atguigu.common.to.mq.OrderTo;
import com.atguigu.common.to.mq.StockLockedTo;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.ware.dao.WareSkuDao;
import com.atguigu.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.atguigu.gulimall.ware.entity.WareOrderTaskEntity;
import com.atguigu.gulimall.ware.entity.WareSkuEntity;
import com.atguigu.gulimall.ware.feign.OrderFeignService;
import com.atguigu.gulimall.ware.feign.ProductFeignService;
import com.atguigu.gulimall.ware.service.WareOrderTaskDetailService;
import com.atguigu.gulimall.ware.service.WareOrderTaskService;
import com.atguigu.gulimall.ware.service.WareSkuService;
import com.atguigu.gulimall.ware.vo.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private WareOrderTaskDetailService detailService;
    @Autowired
    private WareOrderTaskService taskService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OrderFeignService orderFeignService;


    private void unLockStock(Long skuId, Long wareId, Integer skuNum, Long detailId) {
        //解锁库存
        this.baseMapper.unLockStock(skuId, wareId, skuNum);
        //解锁成功，更改状态
        WareOrderTaskDetailEntity detailEntity = new WareOrderTaskDetailEntity();
        detailEntity.setId(detailId);
        detailEntity.setLockStatus(2);
        detailService.updateById(detailEntity);
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        String skuId = (String) params.get("skuId");
        if (StringUtils.hasText(skuId)) {
            wrapper.eq("sku_id", skuId);
        }
        String wareId = (String) params.get("wareId");
        if (StringUtils.hasText(wareId)) {
            wrapper.eq("ware_id", wareId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }

    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        WareSkuEntity wareSku = new WareSkuEntity();
        wareSku.setSkuId(skuId);
        wareSku.setWareId(wareId);
        wareSku.setStock(skuNum);
        wareSku.setStockLocked(0);
        //远程调用product服务查询sku名称
        //远程调用失败，但是仅仅是名称获取失败，我们可以不抛异常，错误设置一个空值即可
        try {
            R info = productFeignService.info(skuId);
            Map<String, Object> skuInfo = (Map<String, Object>) info.get("skuInfo");
            if (info.getCode() == 0) {
                wareSku.setSkuName((String) skuInfo.get("skuName"));
            } else {
                wareSku.setSkuName("");
            }
        } catch (Exception e) {

        }


        int count = this.count(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
        if (count > 0) {
            //数据库有数据，更新
            WareSkuEntity sku = this.getOne(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
            wareSku.setStock(skuNum + sku.getStock());
            UpdateWrapper<WareSkuEntity> wrapper = new UpdateWrapper<>();
            wrapper.eq("sku_id", skuId).eq("ware_id", wareId);
            this.update(wareSku, wrapper);
        } else {
            //数据库无数据，新增
            this.save(wareSku);
        }
    }

    @Override
    public List<SkuHasStockTO> getSKusHasStock(List<Long> skuIds) {
        List<SkuHasStockTO> vos = skuIds.stream().map(skuId -> {
            SkuHasStockTO vo = new SkuHasStockTO();
            Long count = this.baseMapper.getSKusHasStock(skuId);
            vo.setSkuId(skuId);
            //可能为null ，null>0不行
            vo.setHasStock(count == null ? false : count > 0);
            return vo;
        }).collect(Collectors.toList());
        return vos;
    }

    @Transactional
    @Override
    public Boolean orderLockStock(WareSkuLockVo vo) {
        //保存工作单
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        wareOrderTaskEntity.setOrderSn(vo.getOrderSn());
        taskService.save(wareOrderTaskEntity);

        //1.判断商品在哪些仓库有库存
        List<OrderItemVo> locks = vo.getLocks();
        List<SkuWareHasStockVo> hasStockVos = locks.stream().map(item -> {
            Long skuId = item.getSkuId();
            List<Long> wareIdList = this.baseMapper.listWareIdHasSkuStock(skuId);

            SkuWareHasStockVo stockVo = new SkuWareHasStockVo();
            stockVo.setSkuId(skuId);
            stockVo.setWareIds(wareIdList);
            stockVo.setNum(item.getCount());
            return stockVo;
        }).collect(Collectors.toList());

        //2.锁定库存
        for (SkuWareHasStockVo hasStock : hasStockVos) {
            Boolean skuStockLock = false;
            List<Long> wareIds = hasStock.getWareIds();
            //判空
            if (wareIds == null || wareIds.size() == 0) {
                throw new NoStockException(hasStock.getSkuId());
            }

            for (Long wareId : wareIds) {
                Long result = this.baseMapper.lockStock(wareId, hasStock.getSkuId(), hasStock.getNum());
                //1，为更改成功，0为失败
                if (result == 1) {
                    //如果该sku锁定成功，跳出该sku循环
                    skuStockLock = true;
                    //TODO 告诉mq锁定库存成功
                    //保存工作单详情
                    WareOrderTaskDetailEntity taskDetail = new WareOrderTaskDetailEntity(null, hasStock.getSkuId(), "", hasStock.getNum(), wareOrderTaskEntity.getId(), wareId, 1);
                    detailService.save(taskDetail);

                    //属性对拷
                    OrderDetailTo orderDetailTo = new OrderDetailTo();
                    BeanUtils.copyProperties(taskDetail, orderDetailTo);
                    //设置to
                    StockLockedTo stockLockedTo = new StockLockedTo();
                    stockLockedTo.setId(taskDetail.getId());
                    stockLockedTo.setDetailTo(orderDetailTo);


                    //发送消息
                    rabbitTemplate.convertAndSend("stock-event-exchange", "stock.locked", stockLockedTo);


                    break;
                } else {
                    //该仓库失败，重试下一个仓库
                    //TODO rabbitMQ
                }
            }
            if (!skuStockLock) {
                throw new NoStockException(hasStock.getSkuId());
            }

        }
        return true;
    }

    @Override
    public void unLockStock(StockLockedTo to) {
        OrderDetailTo detailTo = to.getDetailTo();
        //解锁库存
        //查询是否有这个订单任务的锁定信息
        //有：
        //   订单号不存在：必须解锁
        //   订单号存在：   订单号已经取消：解锁
        //                没取消：不解锁
        //没有：如果库存锁定失败，回滚了的话就查不到数据，也无需解锁
        WareOrderTaskDetailEntity byId = detailService.getById(detailTo.getId());
        if (byId != null) {
            Long id = to.getId();
            WareOrderTaskEntity task = taskService.getById(id);
            String orderSn = task.getOrderSn();
            R r = orderFeignService.getOrderStatus(orderSn);
            if (r.getCode() == 0) {
                OrderVo data = r.getData(new TypeReference<OrderVo>() {
                });
                //4.为订单已取消状态码
                if (data == null || data.getStatus() == 4) {
                    //解锁
                    if(byId.getLockStatus()==1){
                        unLockStock(detailTo.getSkuId(), detailTo.getWareId(), detailTo.getSkuNum(), detailTo.getId());
                    }
                }

            }else{
                throw new RuntimeException("远程调用失败");
            }
        }else{
            //无需解锁
        }
    }

    @Transactional
    @Override
    public void unLockStock(OrderTo orderTo) {
        //查询taskid
        String orderSn = orderTo.getOrderSn();
        WareOrderTaskEntity orderTaskEntity = taskService.getOne(new QueryWrapper<WareOrderTaskEntity>().eq("order_sn", orderSn));
        Long taskId = orderTaskEntity.getId();

        //对应taskid并且锁定状态为已锁定的
        List<WareOrderTaskDetailEntity> list = detailService.list(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", taskId).eq("lock_status", 1));
        for (WareOrderTaskDetailEntity detailEntity : list) {
            //Long skuId, Long wareId, Integer skuNum, Long detailId
            //解锁库存
            unLockStock(detailEntity.getSkuId(),detailEntity.getWareId(),detailEntity.getSkuNum(),detailEntity.getId());
        }

    }
}